/*
 * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
 *
 * https://www.mall4j.com/
 *
 * 未经允许，不可做商业用途！
 *
 * 版权所有，侵权必究！
 */
package com.yami.shop.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yami.shop.bean.enums.StockBillType;
import com.yami.shop.bean.enums.StockType;
import com.yami.shop.bean.model.Sku;
import com.yami.shop.bean.model.StockBillLog;
import com.yami.shop.bean.model.StockBillLogItem;
import com.yami.shop.bean.vo.StockBillLogItemImportVO;
import com.yami.shop.common.config.Constant;
import com.yami.shop.common.exception.YamiShopBindException;
import com.yami.shop.common.i18n.I18nMessage;
import com.yami.shop.common.i18n.LanguageEnum;
import com.yami.shop.common.util.Arith;
import com.yami.shop.common.util.PageParam;
import com.yami.shop.common.util.PoiExcelUtil;
import com.yami.shop.dao.StockBillLogItemMapper;
import com.yami.shop.service.SkuService;
import com.yami.shop.service.StockBillLogItemService;
import lombok.AllArgsConstructor;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.util.*;

/**
 * 出入库商品项
 *
 * @author LGH
 * @date 2021-09-09 13:11:15
 */
@Service
@AllArgsConstructor
public class StockBillLogItemServiceImpl extends ServiceImpl<StockBillLogItemMapper, StockBillLogItem> implements StockBillLogItemService {

    private final StockBillLogItemMapper stockBillLogItemMapper;
    private final SkuService skuService;

    /**
     * 导入商品项excel列(中文）
     */
    private final static String[] IN_PROD_EXPORT_COL_CN = {
            "商品编码（必填）", "商品名称", "入库数量（必填）"
    };
    /**
     * 导入商品项excel列(英文）
     */
    private final static String[] IN_PROD_EXPORT_COL_EN = {
            "Commodity code (required)", "commodity name", "Warehouse quantity (required)"
    };
    /**
     * 导出商品项excel列(中文）
     */
    private final static String[] OUT_PROD_EXPORT_COL_CN = {
            "商品编码（必填）", "商品名称", "出库数量（必填）"
    };
    /**
     * 导出商品项excel列(英文）
     */
    private final static String[] OUT_PROD_EXPORT_COL_EN = {
            "Commodity code (required)", "product name", "quantity out of stock (required)"
    };

    /**
     * 库存流水excel列(中文)
     */
    private final static String[] STOCK_FLOW_COL_CN = {
            "单据编号", "关联单号", "创建时间", "单据类型", "商品名称", "规格", "商品编码", "出入库", "剩余量", "成本单价", "合计", "操作人"
    };

    /**
     * 库存流水excel列(英文)
     */
    private final static String[] STOCK_FLOW_COL_EN = {
            "stock bill no", "source order no", "creation time", "type of document", "product name", "specification", "hs code", "directly", "remaining quantity", "cost price", "total", "operation"
    };

    @Override
    public List<StockBillLogItem> listByStockBillLogId(Long stockBillLogId) {
        return stockBillLogItemMapper.listCommonProds(stockBillLogId, I18nMessage.getLang());
    }

    @Override
    public void downloadModel(HttpServletResponse response, Integer type) {
        ExcelWriter writer = ExcelUtil.getBigWriter();
        List<String> exportCol = Arrays.asList(
                Objects.equals(I18nMessage.getLang(), LanguageEnum.LANGUAGE_ZH_CN.getLang()) ?
                        Objects.equals(type, StockType.OUT_OF_STOCK.value()) ? OUT_PROD_EXPORT_COL_CN : IN_PROD_EXPORT_COL_CN
                        : Objects.equals(type, StockType.WAREHOUSING.value()) ? OUT_PROD_EXPORT_COL_EN : IN_PROD_EXPORT_COL_EN
        );
        // 最大列数量
        int maxColNum = exportCol.size();
        Sheet sheet = writer.getSheet();
        // 设置列宽
        this.setColumnWidth(sheet);
        // 标题
        writer.merge(maxColNum - 1, Objects.equals(I18nMessage.getLang(), LanguageEnum.LANGUAGE_ZH_CN.getLang()) ?
                Objects.equals(type, StockType.OUT_OF_STOCK.value()) ? "其他出库excel模板" : "其他入库excel模板"
                : Objects.equals(type, StockType.WAREHOUSING.value()) ? "Other outbound excel templates": "Other inbound excel templates"
        );
        // 列名
        writer.writeRow(exportCol);
        PoiExcelUtil.writeExcel(response, writer);
    }

    @Override
    public StockBillLogItemImportVO parseFile(MultipartFile file, Long shopId, Integer type) throws Exception {
        StockBillLogItemImportVO stockBillLogItemImportVO = new StockBillLogItemImportVO();
        try(InputStream inputStream = file.getInputStream();
            Workbook workbook = WorkbookFactory.create(inputStream)) {
            Sheet sheet = workbook.getSheetAt(0);
            int rowNumber = sheet.getPhysicalNumberOfRows();
            if (rowNumber <= Constant.EXCEL_BEGIN_ROW) {
                // 文件无内容
                throw new YamiShopBindException("yami.document.no.content");
            }
            if (!(file.getOriginalFilename().contains(Constant.XLS_FILE) || file.getOriginalFilename().contains(Constant.XLSX_FILE))) {
                // 格式错误
                throw new YamiShopBindException("yami.file.error");
            }
            // 导入数量提醒
            String tips;
            // 错误信息集合
            List<String> errorList = new ArrayList<>();
            // 返回的商品项
            List<StockBillLogItem> stockBillLogItemList = new ArrayList<>();
            Map<String, Integer> skuMap = new HashMap<>(16);
            // 存在数据的条数
            int insertRows = 0;
            List<StockBillLogItem> commonProds = new ArrayList<>();
            List<StockBillLogItem> singleProds = new ArrayList<>();
            for (int i = 2; i < rowNumber; i++) {
                try {
                    Row row = sheet.getRow(i);
                    int cell = -1;
                    // "商品编码（必填）", "商品名称", "出入库数量"
                    String partyCode = PoiExcelUtil.getRowValue(row, ++cell, false);
                    String prodName = PoiExcelUtil.getRowValue(row, ++cell, false);
                    String stockCountStr = PoiExcelUtil.getRowValue(row, ++cell, true);
                    if (StrUtil.isBlank(partyCode) && StrUtil.isBlank(prodName) && Objects.isNull(stockCountStr)) {
                        // 跳过空行
                        continue;
                    }
                    ++insertRows;
                    if (StrUtil.isBlank(partyCode)) {
                        throw new YamiShopBindException("商品编码不能为空");
                    }
                    if (skuMap.containsKey(partyCode)) {
                        throw new YamiShopBindException("当前商品编码与前面的商品编码重复，请删除重复的商品");
                    } else {
                        skuMap.put(partyCode, 1);
                    }
                    addStockBillLogItem(shopId, type, commonProds, partyCode, stockCountStr);
                } catch (Exception e) {
                    //错误信息提示
                    errorList.add("第" + (i + 1) + "行数据有错误：" + e.getMessage());
                }
            }
            stockBillLogItemList.addAll(commonProds);
            stockBillLogItemList.addAll(singleProds);
            tips = "检查到" + insertRows + "条商品信息，成功导入" +
                    (stockBillLogItemList.size()) + "条商品信息！错误" + (insertRows - stockBillLogItemList.size()) + "条商品信息!" +
                    (CollUtil.isNotEmpty(errorList) ? errorList.toString() : "");
            stockBillLogItemImportVO.setTips(tips);
            stockBillLogItemImportVO.setStockBillLogItemList(stockBillLogItemList);
            return stockBillLogItemImportVO;
        } catch (Exception e) {
            stockBillLogItemImportVO.setTips(e.getMessage());
            return stockBillLogItemImportVO;
        }
    }

    private void addStockBillLogItem(Long shopId, Integer type, List<StockBillLogItem> commonProds, String partyCode, String stockCountStr) {
        Sku sku = null;
        sku = skuService.getSkuByShopIdAndPartyCode(shopId, partyCode);
        if (Objects.isNull(sku)) {
            throw new YamiShopBindException("商品不存在");
        }
        if (StrUtil.isBlank(stockCountStr)) {
            throw new YamiShopBindException("数量不能为空");
        }
        Integer stockCount = 0;
        try {
            stockCount = Integer.valueOf(stockCountStr);
        } catch (Exception e) {
            throw new YamiShopBindException("数量必须为纯数字整数");
        }
        if (Objects.equals(type, StockType.OUT_OF_STOCK.value()) && sku.getStocks() < stockCount) {
            throw new YamiShopBindException("出库数量不能超过商品库存");
        }
        StockBillLogItem stockBillLogItem = new StockBillLogItem();
        stockBillLogItem.setProdId(sku.getProdId());
        stockBillLogItem.setSkuId(sku.getSkuId());
        stockBillLogItem.setProdName(sku.getProdName());
        stockBillLogItem.setStocks(sku.getStocks());
        stockBillLogItem.setPic(sku.getPic());
        stockBillLogItem.setPartyCode(sku.getPartyCode());
        stockBillLogItem.setStockCount(stockCount);
        commonProds.add(stockBillLogItem);
    }

    @Override
    public IPage<StockBillLogItem> flow(PageParam<StockBillLog> page, StockBillLog stockBillLog) {
        return stockBillLogItemMapper.flow(page, stockBillLog, I18nMessage.getLang());
    }

    @Override
    public void exportFlow(StockBillLog stockBillLog, HttpServletResponse response) {
        List<StockBillLogItem> stockBillLogItemList = stockBillLogItemMapper.listExport(stockBillLog, I18nMessage.getLang());
        ExcelWriter writer = ExcelUtil.getBigWriter();
        final List<String> exportCol = Arrays.asList(Objects.equals(I18nMessage.getLang(), LanguageEnum.LANGUAGE_ZH_CN.getLang()) ? STOCK_FLOW_COL_CN : STOCK_FLOW_COL_EN);
        // 最大列数量
        int maxColNum = exportCol.size();

        Sheet sheet = writer.getSheet();
        // 设置列宽
        this.setFlowColumnWidth(sheet);
        // 标题
        writer.merge(maxColNum - 1, Objects.equals(I18nMessage.getLang(), LanguageEnum.LANGUAGE_ZH_CN.getLang()) ? "库存流水整理" : "Stock Flow collation");
        // 列名
        writer.writeRow(exportCol);
        int rowIndex = 2;
        for (StockBillLogItem stockBillLogItem : stockBillLogItemList) {
            int col = -1;
            // 单据编号
            PoiExcelUtil.mergeIfNeed(writer, rowIndex, rowIndex, ++col, col, stockBillLogItem.getStockBillNo());
            // 关联单号
            PoiExcelUtil.mergeIfNeed(writer, rowIndex, rowIndex, ++col, col, stockBillLogItem.getSourceOrderNo());
            // 创建时间
            PoiExcelUtil.mergeIfNeed(writer, rowIndex, rowIndex, ++col, col, stockBillLogItem.getCreateTime());
            // 单据类型
            StockBillType stockBillType = StockBillType.instance(stockBillLogItem.getStockBillType());
            PoiExcelUtil.mergeIfNeed(writer, rowIndex, rowIndex, ++col, col, Objects.isNull(stockBillType) ? "" : Objects.equals(I18nMessage.getLang(), LanguageEnum.LANGUAGE_ZH_CN.getLang())?stockBillType.text():stockBillType.textEn());
            // 商品名称
            PoiExcelUtil.mergeIfNeed(writer, rowIndex, rowIndex, ++col, col, stockBillLogItem.getProdName());
            // 规格
            PoiExcelUtil.mergeIfNeed(writer, rowIndex, rowIndex, ++col, col, stockBillLogItem.getSkuName());
            // 商品编码
            PoiExcelUtil.mergeIfNeed(writer, rowIndex, rowIndex, ++col, col, stockBillLogItem.getPartyCode());
            // 出入库
            if(stockBillLogItem.getStockType()==1){
                PoiExcelUtil.mergeIfNeed(writer, rowIndex, rowIndex, ++col, col, "-"+stockBillLogItem.getStockCount());
            }else {
                PoiExcelUtil.mergeIfNeed(writer, rowIndex, rowIndex, ++col, col, "+"+stockBillLogItem.getStockCount());
            }

            // 剩余量
            PoiExcelUtil.mergeIfNeed(writer, rowIndex, rowIndex, ++col, col, stockBillLogItem.getAfterStock());
            // 成本单价
            PoiExcelUtil.mergeIfNeed(writer, rowIndex, rowIndex, ++col, col, stockBillLogItem.getUnitPrice());
            // 合计
            PoiExcelUtil.mergeIfNeed(writer, rowIndex, rowIndex, ++col, col, Arith.mul(stockBillLogItem.getUnitPrice(), stockBillLogItem.getStockCount()));
            // 操作人
            PoiExcelUtil.mergeIfNeed(writer, rowIndex, rowIndex, ++col, col, stockBillLogItem.getEmployeeMobile());
            ++rowIndex;
        }
        PoiExcelUtil.writeExcel(response, writer);
    }

    private void setFlowColumnWidth(Sheet sheet) {
        int i = -1;
        // 单据编号
        sheet.setColumnWidth(++i, 30 * 256);
        // 关联单号
        sheet.setColumnWidth(++i, 30 * 256);
        // 创建时间
        sheet.setColumnWidth(++i, 20 * 256);
        // 单据类型
        sheet.setColumnWidth(++i, 20 * 256);
        // 商品名称
        sheet.setColumnWidth(++i, 30 * 256);
        // 规格
        sheet.setColumnWidth(++i, 20 * 256);
        // 商品编码
        sheet.setColumnWidth(++i, 30 * 256);
        // 出入库
        sheet.setColumnWidth(++i, 20 * 256);
        // 剩余量
        sheet.setColumnWidth(++i, 20 * 256);
        // 成本单价
        sheet.setColumnWidth(++i, 20 * 256);
        // 合计
        sheet.setColumnWidth(++i, 20 * 256);
        // 操作人
        sheet.setColumnWidth(++i, 20 * 256);
    }

    private void setColumnWidth(Sheet sheet) {
        // 商品编码（必填）
        sheet.setColumnWidth(0, 40 * 256);
        // 商品名称
        sheet.setColumnWidth(1, 40 * 256);
        // 出/入库数量（必填）
        sheet.setColumnWidth(2, 20 * 256);
    }
}
